package bus_srv

import (
	"encoding/json"
	"fmt"
	apis2 "gluenet/pkg/apis"
	"gluenet/pkg/meta"
	rpc "gluenet/utils/rpc/define"
	v2 "gluenet/utils/rpc/v2/define"
)

//func GuidRegister(ctx *apis.GlueContext) {
//	ctx.Logger.Debugf("receive register")
//	req := rpc.GuidRegisterRequest{}
//	if err := json.Unmarshal(ctx.RpcContext.Data.Data, &req); err != nil {
//		ctx.Logger.Debugf("unmarshall err %v", err)
//		return
//	}
//
//	var resp *rpc.GuidRegisterResponse
//	switch req.Type {
//	case rpc.GuidTypeRegister:
//		ctx.Logger.Debugf("type register")
//
//		Re, err := ctx.Rpc.Request(apis.GuidServiceRegister, []byte("dddd"))
//		if err != nil {
//			ctx.Logger.Errorf("request guid %v", err)
//			return
//		}
//
//		rp := apis.IResponse{}
//		if err = json.Unmarshal(Re, &rp); err != nil {
//			ctx.Logger.Errorf("unmarshall guid %v", err)
//			return
//		}
//
//		ctx.Logger.Debugf("get guid %s", Re)
//
//		req.Agent.StatusInfo.Guid = rp.Data.(string)
//		agent := v1.BusAgentToAgent(req.Agent)
//
//		if _, err = ctx.DataBase.InsertOne(impl.SqlDataBase, agent); err != nil {
//			ctx.Logger.Errorf("insert agent %v", err)
//			return
//		}
//
//		if _, err = ctx.DataBase.InsertOne(impl.SqlDataBase, tables.GNode{
//			Label: "",
//			Guid:  agent.Guid,
//			Type:  tables.TypeNodeAgentsHost,
//		}); err != nil {
//			ctx.Logger.Errorf("insert node %v", err)
//			return
//		}
//
//		resp = &rpc.GuidRegisterResponse{
//			Agent: req.Agent,
//		}
//	case rpc.GuidTypeUnRegister:
//		ctx.Logger.Debugf("type unregister failed")
//
//		_, err := ctx.Rpc.Request(apis.GuidServiceUnRegister, []byte("dddd"))
//		if err != nil {
//			ctx.Logger.Errorf("request guid %v", err)
//			return
//		}
//
//		agent := v1.BusAgentToAgent(req.Agent)
//		if _, err = ctx.DataBase.Delete(impl.SqlDataBase, agent); err != nil {
//			ctx.Logger.Errorf("request guid %v", err)
//			return
//		}
//
//		if _, err = ctx.DataBase.Delete(impl.SqlDataBase, tables.GNode{
//			Label: "",
//			Guid:  agent.Guid,
//			Type:  tables.TypeNodeAgentsHost,
//		}); err != nil {
//			ctx.Logger.Errorf("request guid %v", err)
//			return
//		}
//
//		resp = &rpc.GuidRegisterResponse{
//			Agent: req.Agent.Clone(),
//		}
//	}
//
//	resBytes, err := json.Marshal(resp)
//	if err != nil {
//		ctx.Logger.Errorf("marshall resp %v", err)
//	}
//
//	if err = ctx.RpcContext.Data.IRespond(resBytes); err != nil {
//		ctx.Logger.Errorf("response guid %v", err)
//	} else {
//		ctx.Logger.Debugf("rpc guid register return %s", resBytes)
//	}
//}

func GuidRegisterNew(ctx *apis2.GlueContext) {
	ctx.Logger.Debugf("receive register")

	req := v2.GuidRequest{}
	if err := json.Unmarshal(ctx.RpcContext.Data.Data, &req); err != nil {
		ctx.Logger.Debugf("unmarshall err %v", err)
		return
	}

	var resp *v2.GuidResponse
	switch req.Type {
	case rpc.GuidTypeRegister:
		ctx.Logger.Debugf("type register")

		guid, err := registerGuid(ctx, req.Agent)
		if err != nil {
			ctx.Logger.Errorf("register guid %v", err)
			return
		}

		req.Agent.Guid = guid

		if err := save(ctx, req.Agent); err != nil {
			if err != nil {
				ctx.Logger.Errorf("register guid %v", err)
				return
			}
		}

		resp = &v2.GuidResponse{
			Guid: guid,
		}
	case rpc.GuidTypeUnRegister:
		ctx.Logger.Debugf("type unregister failed")

		if err := unregisterGuid(ctx, req.Agent); err != nil {
			ctx.Logger.Errorf("un register guid %v", err)
			return
		}

		if err := delete(ctx, req.Agent); err != nil {
			ctx.Logger.Errorf("delete agent info %v", err)
			return
		}

		resp = &v2.GuidResponse{
			Guid: req.Agent.Guid,
		}
	}

	resBytes, err := json.Marshal(resp)
	if err != nil {
		ctx.Logger.Errorf("marshall resp %v", err)
	}

	if err = ctx.RpcContext.Data.IRespond(resBytes); err != nil {
		ctx.Logger.Errorf("response guid %v", err)
	} else {
		ctx.Logger.Debugf("rpc guid register return %s", resBytes)
	}
}

func registerGuid(ctx *apis2.GlueContext, agent *v2.AgentInfo) (string, error) {
	data, _ := json.Marshal(agent)

	respBytes, err := ctx.Rpc.Request(apis2.GuidServiceRegister, data)
	if err != nil {
		return "", err
	}

	resp := apis2.IResponse{}
	if err = json.Unmarshal(respBytes, &resp); err != nil {
		return "", err
	}

	return resp.Data.(string), nil
}

func unregisterGuid(ctx *apis2.GlueContext, agent *v2.AgentInfo) error {
	data, _ := json.Marshal(agent)

	_, err := ctx.Rpc.Request(apis2.GuidServiceUnRegister, data)
	if err != nil {
		return err
	}

	return nil
}

func save(ctx *apis2.GlueContext, agent *v2.AgentInfo) error {
	var ags = []meta.AgentStatus{}
	if err := ctx.DataBase.MetaDB().SQL(`select * from agent_status where guid = ?`, agent.Guid).Find(&ags); err != nil {
		return err
	}

	// 重连，之前有数据存在
	if len(ags) > 0 {
		return nil
	}

	info, statu := apis2.BusAgentToAgent(agent)
	tags, err := meta.DeCodeTags(statu.Tags)
	if err != nil {
		return err
	}

	platform, ok := tags["platform"]
	if !ok {
		return fmt.Errorf("need platform in tags")
	}

	session := ctx.DataBase.MetaDB().NewSession()
	if _, err = session.InsertOne(info); err != nil {
		session.Rollback()
		return err
	}
	if _, err = session.InsertOne(statu); err != nil {
		session.Rollback()
		return err
	}
	if err = session.Commit(); err != nil {
		session.Rollback()
		return err
	}

	var arun = meta.AgentRunTime{
		AgentGuid: info.Guid,
		Platform:  platform,
		Hosts:     info.Hostname,
	}

	ctx.DataBase.AgentRuntimePut(&arun)

	return nil
}

func delete(ctx *apis2.GlueContext, agent *v2.AgentInfo) error {
	if _, err := ctx.DataBase.MetaDB().Exec(`DELETE FROM agent_info WHERE guid=?`,
		agent.Guid); err != nil {
		return err
	}
	return nil
}
